home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / DB / common.php < prev    next >
PHP Script  |  2004-10-01  |  63KB  |  2,043 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Stig Bakken <ssb@php.net>                                    |
  17. // |         Tomas V.V.Cox <cox@idecnet.com>                              |
  18. // | Maintainer: Daniel Convissor <danielc@php.net>                       |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: common.php,v 1.103 2004/06/24 15:24:56 danielc Exp $
  22.  
  23. require_once 'PEAR.php';
  24.  
  25. /**
  26.  * DB_common is a base class for DB implementations, and must be
  27.  * inherited by all such
  28.  *
  29.  * @package  DB
  30.  * @version  $Id: common.php,v 1.103 2004/06/24 15:24:56 danielc Exp $
  31.  * @category Database
  32.  * @author   Stig Bakken <ssb@php.net>
  33.  * @author   Tomas V.V.Cox <cox@idecnet.com>
  34.  */
  35. class DB_common extends PEAR
  36. {
  37.     // {{{ properties
  38.  
  39.     /**
  40.      * assoc of capabilities for this DB implementation
  41.      * $features['limit'] =>  'emulate' => emulate with fetch row by number
  42.      *                        'alter'   => alter the query
  43.      *                        false     => skip rows
  44.      * @var array
  45.      */
  46.     var $features = array();
  47.  
  48.     /**
  49.      * assoc mapping native error codes to DB ones
  50.      * @var array
  51.      */
  52.     var $errorcode_map = array();
  53.  
  54.     /**
  55.      * DB type (mysql, oci8, odbc etc.)
  56.      * @var string
  57.      */
  58.     var $phptype;
  59.  
  60.     /**
  61.      * @var string
  62.      */
  63.     var $prepare_tokens;
  64.  
  65.     /**
  66.      * @var string
  67.      */
  68.     var $prepare_types;
  69.  
  70.     /**
  71.      * @var string
  72.      */
  73.     var $prepared_queries;
  74.  
  75.     /**
  76.      * @var integer
  77.      */
  78.     var $prepare_maxstmt = 0;
  79.  
  80.     /**
  81.      * @var string
  82.      */
  83.     var $last_query = '';
  84.  
  85.     /**
  86.      * @var integer
  87.      */
  88.     var $fetchmode = DB_FETCHMODE_ORDERED;
  89.  
  90.     /**
  91.      * @var string
  92.      */
  93.     var $fetchmode_object_class = 'stdClass';
  94.  
  95.     /**
  96.      * Run-time configuration options.
  97.      *
  98.      * The 'optimize' option has been deprecated.  Use the 'portability'
  99.      * option instead.
  100.      *
  101.      * @see DB_common::setOption()
  102.      * @var array
  103.      */
  104.     var $options = array(
  105.         'persistent' => false,
  106.         'ssl' => false,
  107.         'debug' => 0,
  108.         'seqname_format' => '%s_seq',
  109.         'autofree' => false,
  110.         'portability' => DB_PORTABILITY_NONE,
  111.         'optimize' => 'performance',  // Deprecated.  Use 'portability'.
  112.     );
  113.  
  114.     /**
  115.      * DB handle
  116.      * @var resource
  117.      */
  118.     var $dbh;
  119.  
  120.     // }}}
  121.     // {{{ toString()
  122.  
  123.     /**
  124.      * String conversation
  125.      *
  126.      * @return string
  127.      * @access private
  128.      */
  129.     function toString()
  130.     {
  131.         $info = strtolower(get_class($this));
  132.         $info .=  ': (phptype=' . $this->phptype .
  133.                   ', dbsyntax=' . $this->dbsyntax .
  134.                   ')';
  135.  
  136.         if ($this->connection) {
  137.             $info .= ' [connected]';
  138.         }
  139.  
  140.         return $info;
  141.     }
  142.  
  143.     // }}}
  144.     // {{{ constructor
  145.  
  146.     /**
  147.      * Constructor
  148.      */
  149.     function DB_common()
  150.     {
  151.         $this->PEAR('DB_Error');
  152.     }
  153.  
  154.     // }}}
  155.     // {{{ quoteString()
  156.  
  157.     /**
  158.      * DEPRECATED: Quotes a string so it can be safely used within string
  159.      * delimiters in a query
  160.      *
  161.      * @return string quoted string
  162.      *
  163.      * @see DB_common::quoteSmart(), DB_common::escapeSimple()
  164.      * @deprecated  Deprecated in release 1.2 or lower
  165.      * @internal
  166.      */
  167.     function quoteString($string)
  168.     {
  169.         $string = $this->quote($string);
  170.         if ($string{0} == "'") {
  171.             return substr($string, 1, -1);
  172.         }
  173.         return $string;
  174.     }
  175.  
  176.     // }}}
  177.     // {{{ quote()
  178.  
  179.     /**
  180.      * DEPRECATED: Quotes a string so it can be safely used in a query
  181.      *
  182.      * @param string $string the input string to quote
  183.      *
  184.      * @return string The NULL string or the string quotes
  185.      *                in magic_quote_sybase style
  186.      *
  187.      * @see DB_common::quoteSmart(), DB_common::escapeSimple()
  188.      * @deprecated  Deprecated in release 1.6.0
  189.      * @internal
  190.      */
  191.     function quote($string = null)
  192.     {
  193.         return ($string === null) ? 'NULL' : "'".str_replace("'", "''", $string)."'";
  194.     }
  195.  
  196.     // }}}
  197.     // {{{ quoteIdentifier()
  198.  
  199.     /**
  200.      * Quote a string so it can be safely used as a table or column name
  201.      *
  202.      * Delimiting style depends on which database driver is being used.
  203.      *
  204.      * NOTE: just because you CAN use delimited identifiers doesn't mean
  205.      * you SHOULD use them.  In general, they end up causing way more
  206.      * problems than they solve.
  207.      *
  208.      * Portability is broken by using the following characters inside
  209.      * delimited identifiers:
  210.      *   + backtick (<kbd>`</kbd>) -- due to MySQL
  211.      *   + double quote (<kbd>"</kbd>) -- due to Oracle
  212.      *   + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
  213.      *
  214.      * Delimited identifiers are known to generally work correctly under
  215.      * the following drivers:
  216.      *   + mssql
  217.      *   + mysql
  218.      *   + mysqli
  219.      *   + oci8
  220.      *   + odbc(access)
  221.      *   + odbc(db2)
  222.      *   + pgsql
  223.      *   + sqlite
  224.      *   + sybase
  225.      *
  226.      * InterBase doesn't seem to be able to use delimited identifiers
  227.      * via PHP 4.  They work fine under PHP 5.
  228.      *
  229.      * @param string $str  identifier name to be quoted
  230.      *
  231.      * @return string  quoted identifier string
  232.      *
  233.      * @since 1.6.0
  234.      * @access public
  235.      */
  236.     function quoteIdentifier($str)
  237.     {
  238.         return '"' . str_replace('"', '""', $str) . '"';
  239.     }
  240.  
  241.     // }}}
  242.     // {{{ quoteSmart()
  243.  
  244.     /**
  245.      * Format input so it can be safely used in a query
  246.      *
  247.      * The output depends on the PHP data type of input and the database
  248.      * type being used.
  249.      *
  250.      * @param mixed $in  data to be quoted
  251.      *
  252.      * @return mixed  the format of the results depends on the input's
  253.      *                PHP type:
  254.      *
  255.      * <ul>
  256.      *  <li>
  257.      *    <kbd>input</kbd> -> <samp>returns</samp>
  258.      *  </li>
  259.      *  <li>
  260.      *    <kbd>null</kbd> -> the string <samp>NULL</samp>
  261.      *  </li>
  262.      *  <li>
  263.      *    <kbd>integer</kbd> or <kbd>double</kbd> -> the unquoted number
  264.      *  </li>
  265.      *  <li>
  266.      *    &type.bool; -> output depends on the driver in use
  267.      *    Most drivers return integers: <samp>1</samp> if
  268.      *    <kbd>true</kbd> or <samp>0</samp> if
  269.      *    <kbd>false</kbd>.
  270.      *    Some return strings: <samp>TRUE</samp> if
  271.      *    <kbd>true</kbd> or <samp>FALSE</samp> if
  272.      *    <kbd>false</kbd>.
  273.      *    Finally one returns strings: <samp>T</samp> if
  274.      *    <kbd>true</kbd> or <samp>F</samp> if
  275.      *    <kbd>false</kbd>. Here is a list of each DBMS,
  276.      *    the values returned and the suggested column type:
  277.      *    <ul>
  278.      *      <li>
  279.      *        <kbd>dbase</kbd> -> <samp>T/F</samp>
  280.      *        (<kbd>Logical</kbd>)
  281.      *      </li>
  282.      *      <li>
  283.      *        <kbd>fbase</kbd> -> <samp>TRUE/FALSE</samp>
  284.      *        (<kbd>BOOLEAN</kbd>)
  285.      *      </li>
  286.      *      <li>
  287.      *        <kbd>ibase</kbd> -> <samp>1/0</samp>
  288.      *        (<kbd>SMALLINT</kbd>) [1]
  289.      *      </li>
  290.      *      <li>
  291.      *        <kbd>ifx</kbd> -> <samp>1/0</samp>
  292.      *        (<kbd>SMALLINT</kbd>) [1]
  293.      *      </li>
  294.      *      <li>
  295.      *        <kbd>msql</kbd> -> <samp>1/0</samp>
  296.      *        (<kbd>INTEGER</kbd>)
  297.      *      </li>
  298.      *      <li>
  299.      *        <kbd>mssql</kbd> -> <samp>1/0</samp>
  300.      *        (<kbd>BIT</kbd>)
  301.      *      </li>
  302.      *      <li>
  303.      *        <kbd>mysql</kbd> -> <samp>1/0</samp>
  304.      *        (<kbd>TINYINT(1)</kbd>)
  305.      *      </li>
  306.      *      <li>
  307.      *        <kbd>mysqli</kbd> -> <samp>1/0</samp>
  308.      *        (<kbd>TINYINT(1)</kbd>)
  309.      *      </li>
  310.      *      <li>
  311.      *        <kbd>oci8</kbd> -> <samp>1/0</samp>
  312.      *        (<kbd>NUMBER(1)</kbd>)
  313.      *      </li>
  314.      *      <li>
  315.      *        <kbd>odbc</kbd> -> <samp>1/0</samp>
  316.      *        (<kbd>SMALLINT</kbd>) [1]
  317.      *      </li>
  318.      *      <li>
  319.      *        <kbd>pgsql</kbd> -> <samp>TRUE/FALSE</samp>
  320.      *        (<kbd>BOOLEAN</kbd>)
  321.      *      </li>
  322.      *      <li>
  323.      *        <kbd>sqlite</kbd> -> <samp>1/0</samp>
  324.      *        (<kbd>INTEGER</kbd>)
  325.      *      </li>
  326.      *      <li>
  327.      *        <kbd>sybase</kbd> -> <samp>1/0</samp>
  328.      *        (<kbd>TINYINT(1)</kbd>)
  329.      *      </li>
  330.      *    </ul>
  331.      *    [1] Accommodate the lowest common denominator because not all
  332.      *    versions of have <kbd>BOOLEAN</kbd>.
  333.      *  </li>
  334.      *  <li>
  335.      *    other (including strings and numeric strings) ->
  336.      *    the data with single quotes escaped by preceeding
  337.      *    single quotes, backslashes are escaped by preceeding
  338.      *    backslashes, then the whole string is encapsulated
  339.      *    between single quotes
  340.      *  </li>
  341.      * </ul>
  342.      *
  343.      * @since 1.6.0
  344.      * @see DB_common::escapeSimple()
  345.      * @access public
  346.      */
  347.     function quoteSmart($in)
  348.     {
  349.         if (is_int($in) || is_double($in)) {
  350.             return $in;
  351.         } elseif (is_bool($in)) {
  352.             return $in ? 1 : 0;
  353.         } elseif (is_null($in)) {
  354.             return 'NULL';
  355.         } else {
  356.             return "'" . $this->escapeSimple($in) . "'";
  357.         }
  358.     }
  359.  
  360.     // }}}
  361.     // {{{ escapeSimple()
  362.  
  363.     /**
  364.      * Escape a string according to the current DBMS's standards
  365.      *
  366.      * In SQLite, this makes things safe for inserts/updates, but may
  367.      * cause problems when performing text comparisons against columns
  368.      * containing binary data. See the
  369.      * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
  370.      *
  371.      * @param string $str  the string to be escaped
  372.      *
  373.      * @return string  the escaped string
  374.      *
  375.      * @since 1.6.0
  376.      * @see DB_common::quoteSmart()
  377.      * @access public
  378.      */
  379.     function escapeSimple($str) {
  380.         return str_replace("'", "''", $str);
  381.     }
  382.  
  383.     // }}}
  384.     // {{{ provides()
  385.  
  386.     /**
  387.      * Tell whether a DB implementation or its backend extension
  388.      * supports a given feature
  389.      *
  390.      * @param array $feature name of the feature (see the DB class doc)
  391.      * @return bool whether this DB implementation supports $feature
  392.      * @access public
  393.      */
  394.     function provides($feature)
  395.     {
  396.         return $this->features[$feature];
  397.     }
  398.  
  399.     // }}}
  400.     // {{{ errorCode()
  401.  
  402.     /**
  403.      * Map native error codes to DB's portable ones
  404.      *
  405.      * Requires that the DB implementation's constructor fills
  406.      * in the <var>$errorcode_map</var> property.
  407.      *
  408.      * @param mixed  $nativecode  the native error code, as returned by the
  409.      * backend database extension (string or integer)
  410.      *
  411.      * @return int a portable DB error code, or DB_ERROR if this DB
  412.      * implementation has no mapping for the given error code.
  413.      *
  414.      * @access public
  415.      */
  416.     function errorCode($nativecode)
  417.     {
  418.         if (isset($this->errorcode_map[$nativecode])) {
  419.             return $this->errorcode_map[$nativecode];
  420.         }
  421.         // Fall back to DB_ERROR if there was no mapping.
  422.         return DB_ERROR;
  423.     }
  424.  
  425.     // }}}
  426.     // {{{ errorMessage()
  427.  
  428.     /**
  429.      * Map a DB error code to a textual message.  This is actually
  430.      * just a wrapper for DB::errorMessage()
  431.      *
  432.      * @param integer $dbcode the DB error code
  433.      *
  434.      * @return string the corresponding error message, of false
  435.      * if the error code was unknown
  436.      *
  437.      * @access public
  438.      */
  439.     function errorMessage($dbcode)
  440.     {
  441.         return DB::errorMessage($this->errorcode_map[$dbcode]);
  442.     }
  443.  
  444.     // }}}
  445.     // {{{ raiseError()
  446.  
  447.     /**
  448.      * Communicate an error and invoke error callbacks, etc
  449.      *
  450.      * Basically a wrapper for PEAR::raiseError without the message string.
  451.      *
  452.      * @param mixed    integer error code, or a PEAR error object (all
  453.      *                 other parameters are ignored if this parameter is
  454.      *                 an object
  455.      *
  456.      * @param int      error mode, see PEAR_Error docs
  457.      *
  458.      * @param mixed    If error mode is PEAR_ERROR_TRIGGER, this is the
  459.      *                 error level (E_USER_NOTICE etc).  If error mode is
  460.      *                 PEAR_ERROR_CALLBACK, this is the callback function,
  461.      *                 either as a function name, or as an array of an
  462.      *                 object and method name.  For other error modes this
  463.      *                 parameter is ignored.
  464.      *
  465.      * @param string   Extra debug information.  Defaults to the last
  466.      *                 query and native error code.
  467.      *
  468.      * @param mixed    Native error code, integer or string depending the
  469.      *                 backend.
  470.      *
  471.      * @return object  a PEAR error object
  472.      *
  473.      * @access public
  474.      * @see PEAR_Error
  475.      */
  476.     function &raiseError($code = DB_ERROR, $mode = null, $options = null,
  477.                          $userinfo = null, $nativecode = null)
  478.     {
  479.         // The error is yet a DB error object
  480.         if (is_object($code)) {
  481.             // because we the static PEAR::raiseError, our global
  482.             // handler should be used if it is set
  483.             if ($mode === null && !empty($this->_default_error_mode)) {
  484.                 $mode    = $this->_default_error_mode;
  485.                 $options = $this->_default_error_options;
  486.             }
  487.             $tmp = PEAR::raiseError($code, null, $mode, $options, null, null, true);
  488.             return $tmp;
  489.         }
  490.  
  491.         if ($userinfo === null) {
  492.             $userinfo = $this->last_query;
  493.         }
  494.  
  495.         if ($nativecode) {
  496.             $userinfo .= ' [nativecode=' . trim($nativecode) . ']';
  497.         }
  498.  
  499.         $tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo,
  500.                                 'DB_Error', true);
  501.         return $tmp;
  502.     }
  503.  
  504.     // }}}
  505.     // {{{ setFetchMode()
  506.  
  507.     /**
  508.      * Sets which fetch mode should be used by default on queries
  509.      * on this connection
  510.      *
  511.      * @param integer $fetchmode DB_FETCHMODE_ORDERED or
  512.      *        DB_FETCHMODE_ASSOC, possibly bit-wise OR'ed with
  513.      *        DB_FETCHMODE_FLIPPED.
  514.      *
  515.      * @param string $object_class The class of the object
  516.      *                      to be returned by the fetch methods when
  517.      *                      the DB_FETCHMODE_OBJECT mode is selected.
  518.      *                      If no class is specified by default a cast
  519.      *                      to object from the assoc array row will be done.
  520.      *                      There is also the posibility to use and extend the
  521.      *                      'DB_row' class.
  522.      *
  523.      * @see DB_FETCHMODE_ORDERED
  524.      * @see DB_FETCHMODE_ASSOC
  525.      * @see DB_FETCHMODE_FLIPPED
  526.      * @see DB_FETCHMODE_OBJECT
  527.      * @see DB_row::DB_row()
  528.      * @access public
  529.      */
  530.     function setFetchMode($fetchmode, $object_class = 'stdClass')
  531.     {
  532.         switch ($fetchmode) {
  533.             case DB_FETCHMODE_OBJECT:
  534.                 $this->fetchmode_object_class = $object_class;
  535.             case DB_FETCHMODE_ORDERED:
  536.             case DB_FETCHMODE_ASSOC:
  537.                 $this->fetchmode = $fetchmode;
  538.                 break;
  539.             default:
  540.                 return $this->raiseError('invalid fetchmode mode');
  541.         }
  542.     }
  543.  
  544.     // }}}
  545.     // {{{ setOption()
  546.  
  547.     /**
  548.      * Set run-time configuration options for PEAR DB
  549.      *
  550.      * Options, their data types, default values and description:
  551.      * <ul>
  552.      * <li>
  553.      * <var>autofree</var> <kbd>boolean</kbd> = <samp>false</samp>
  554.      *      <br />should results be freed automatically when there are no
  555.      *            more rows?
  556.      * </li><li>
  557.      * <var>debug</var> <kbd>integer</kbd> = <samp>0</samp>
  558.      *      <br />debug level
  559.      * </li><li>
  560.      * <var>persistent</var> <kbd>boolean</kbd> = <samp>false</samp>
  561.      *      <br />should the connection be persistent?
  562.      * </li><li>
  563.      * <var>portability</var> <kbd>integer</kbd> = <samp>DB_PORTABILITY_NONE</samp>
  564.      *      <br />portability mode constant (see below)
  565.      * </li><li>
  566.      * <var>seqname_format</var> <kbd>string</kbd> = <samp>%s_seq</samp>
  567.      *      <br />the sprintf() format string used on sequence names.  This
  568.      *            format is applied to sequence names passed to
  569.      *            createSequence(), nextID() and dropSequence().
  570.      * </li><li>
  571.      * <var>ssl</var> <kbd>boolean</kbd> = <samp>false</samp>
  572.      *      <br />use ssl to connect?
  573.      * </li>
  574.      * </ul>
  575.      *
  576.      * -----------------------------------------
  577.      *
  578.      * PORTABILITY MODES
  579.      *
  580.      * These modes are bitwised, so they can be combined using <kbd>|</kbd>
  581.      * and removed using <kbd>^</kbd>.  See the examples section below on how
  582.      * to do this.
  583.      *
  584.      * <samp>DB_PORTABILITY_NONE</samp>
  585.      * turn off all portability features
  586.      *
  587.      * This mode gets automatically turned on if the deprecated
  588.      * <var>optimize</var> option gets set to <samp>performance</samp>.
  589.      *
  590.      *
  591.      * <samp>DB_PORTABILITY_LOWERCASE</samp>
  592.      * convert names of tables and fields to lower case when using
  593.      * <kbd>get*()</kbd>, <kbd>fetch*()</kbd> and <kbd>tableInfo()</kbd>
  594.      *
  595.      * This mode gets automatically turned on in the following databases
  596.      * if the deprecated option <var>optimize</var> gets set to
  597.      * <samp>portability</samp>:
  598.      * + oci8
  599.      *
  600.      *
  601.      * <samp>DB_PORTABILITY_RTRIM</samp>
  602.      * right trim the data output by <kbd>get*()</kbd> <kbd>fetch*()</kbd>
  603.      *
  604.      *
  605.      * <samp>DB_PORTABILITY_DELETE_COUNT</samp>
  606.      * force reporting the number of rows deleted
  607.      *
  608.      * Some DBMS's don't count the number of rows deleted when performing
  609.      * simple <kbd>DELETE FROM tablename</kbd> queries.  This portability
  610.      * mode tricks such DBMS's into telling the count by adding
  611.      * <samp>WHERE 1=1</samp> to the end of <kbd>DELETE</kbd> queries.
  612.      *
  613.      * This mode gets automatically turned on in the following databases
  614.      * if the deprecated option <var>optimize</var> gets set to
  615.      * <samp>portability</samp>:
  616.      * + fbsql
  617.      * + mysql
  618.      * + mysqli
  619.      * + sqlite
  620.      *
  621.      *
  622.      * <samp>DB_PORTABILITY_NUMROWS</samp>
  623.      * enable hack that makes <kbd>numRows()</kbd> work in Oracle
  624.      *
  625.      * This mode gets automatically turned on in the following databases
  626.      * if the deprecated option <var>optimize</var> gets set to
  627.      * <samp>portability</samp>:
  628.      * + oci8
  629.      *
  630.      *
  631.      * <samp>DB_PORTABILITY_ERRORS</samp>
  632.      * makes certain error messages in certain drivers compatible
  633.      * with those from other DBMS's
  634.      *
  635.      * + mysql, mysqli:  change unique/primary key constraints
  636.      *   DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT
  637.      *
  638.      * + odbc(access):  MS's ODBC driver reports 'no such field' as code
  639.      *   07001, which means 'too few parameters.'  When this option is on
  640.      *   that code gets mapped to DB_ERROR_NOSUCHFIELD.
  641.      *   DB_ERROR_MISMATCH -> DB_ERROR_NOSUCHFIELD
  642.      *
  643.      *
  644.      * <samp>DB_PORTABILITY_NULL_TO_EMPTY</samp>
  645.      * convert null values to empty strings in data output by get*() and
  646.      * fetch*().  Needed because Oracle considers empty strings to be null,
  647.      * while most other DBMS's know the difference between empty and null.
  648.      *
  649.      *
  650.      * <samp>DB_PORTABILITY_ALL</samp>
  651.      * turn on all portability features
  652.      *
  653.      * -----------------------------------------
  654.      *
  655.      * Example 1. Simple setOption() example
  656.      * <code> <?php
  657.      * $dbh->setOption('autofree', true);
  658.      * ?></code>
  659.      *
  660.      * Example 2. Portability for lowercasing and trimming
  661.      * <code> <?php
  662.      * $dbh->setOption('portability',
  663.      *                  DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_RTRIM);
  664.      * ?></code>
  665.      *
  666.      * Example 3. All portability options except trimming
  667.      * <code> <?php
  668.      * $dbh->setOption('portability',
  669.      *                  DB_PORTABILITY_ALL ^ DB_PORTABILITY_RTRIM);
  670.      * ?></code>
  671.      *
  672.      * @param string $option option name
  673.      * @param mixed  $value value for the option
  674.      *
  675.      * @return int  DB_OK on success.  DB_Error object on failure.
  676.      *
  677.      * @see DB_common::$options
  678.      */
  679.     function setOption($option, $value)
  680.     {
  681.         if (isset($this->options[$option])) {
  682.             $this->options[$option] = $value;
  683.  
  684.             /*
  685.              * Backwards compatibility check for the deprecated 'optimize'
  686.              * option.  Done here in case settings change after connecting.
  687.              */
  688.             if ($option == 'optimize') {
  689.                 if ($value == 'portability') {
  690.                     switch ($this->phptype) {
  691.                         case 'oci8':
  692.                             $this->options['portability'] =
  693.                                     DB_PORTABILITY_LOWERCASE |
  694.                                     DB_PORTABILITY_NUMROWS;
  695.                             break;
  696.                         case 'fbsql':
  697.                         case 'mysql':
  698.                         case 'mysqli':
  699.                         case 'sqlite':
  700.                             $this->options['portability'] =
  701.                                     DB_PORTABILITY_DELETE_COUNT;
  702.                             break;
  703.                     }
  704.                 } else {
  705.                     $this->options['portability'] = DB_PORTABILITY_NONE;
  706.                 }
  707.             }
  708.  
  709.             return DB_OK;
  710.         }
  711.         return $this->raiseError("unknown option $option");
  712.     }
  713.  
  714.     // }}}
  715.     // {{{ getOption()
  716.  
  717.     /**
  718.      * Returns the value of an option
  719.      *
  720.      * @param string $option option name
  721.      *
  722.      * @return mixed the option value
  723.      */
  724.     function getOption($option)
  725.     {
  726.         if (isset($this->options[$option])) {
  727.             return $this->options[$option];
  728.         }
  729.         return $this->raiseError("unknown option $option");
  730.     }
  731.  
  732.     // }}}
  733.     // {{{ prepare()
  734.  
  735.     /**
  736.      * Prepares a query for multiple execution with execute()
  737.      *
  738.      * Creates a query that can be run multiple times.  Each time it is run,
  739.      * the placeholders, if any, will be replaced by the contents of
  740.      * execute()'s $data argument.
  741.      *
  742.      * Three types of placeholders can be used:
  743.      *   + <kbd>?</kbd>  scalar value (i.e. strings, integers).  The system
  744.      *                   will automatically quote and escape the data.
  745.      *   + <kbd>!</kbd>  value is inserted 'as is'
  746.      *   + <kbd>&</kbd>  requires a file name.  The file's contents get
  747.      *                   inserted into the query (i.e. saving binary
  748.      *                   data in a db)
  749.      *
  750.      * Example 1.
  751.      * <code> <?php
  752.      * $sth = $dbh->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)');
  753.      * $data = array(
  754.      *     "John's text",
  755.      *     "'it''s good'",
  756.      *     'filename.txt'
  757.      * );
  758.      * $res = $dbh->execute($sth, $data);
  759.      * ?></code>
  760.      *
  761.      * Use backslashes to escape placeholder characters if you don't want
  762.      * them to be interpreted as placeholders:
  763.      * <pre>
  764.      *    "UPDATE foo SET col=? WHERE col='over \& under'"
  765.      * </pre>
  766.      *
  767.      * With some database backends, this is emulated.
  768.      *
  769.      * {@internal ibase and oci8 have their own prepare() methods.}}
  770.      *
  771.      * @param string $query query to be prepared
  772.      *
  773.      * @return mixed DB statement resource on success. DB_Error on failure.
  774.      *
  775.      * @see DB_common::execute()
  776.      * @access public
  777.      */
  778.     function prepare($query)
  779.     {
  780.         $tokens   = preg_split('/((?<!\\\)[&?!])/', $query, -1,
  781.                                PREG_SPLIT_DELIM_CAPTURE);
  782.         $token     = 0;
  783.         $types     = array();
  784.         $newtokens = array();
  785.  
  786.         foreach ($tokens as $val) {
  787.             switch ($val) {
  788.                 case '?':
  789.                     $types[$token++] = DB_PARAM_SCALAR;
  790.                     break;
  791.                 case '&':
  792.                     $types[$token++] = DB_PARAM_OPAQUE;
  793.                     break;
  794.                 case '!':
  795.                     $types[$token++] = DB_PARAM_MISC;
  796.                     break;
  797.                 default:
  798.                     $newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val);
  799.             }
  800.         }
  801.  
  802.         $this->prepare_tokens[] = &$newtokens;
  803.         end($this->prepare_tokens);
  804.  
  805.         $k = key($this->prepare_tokens);
  806.         $this->prepare_types[$k] = $types;
  807.         $this->prepared_queries[$k] = implode(' ', $newtokens);
  808.  
  809.         return $k;
  810.     }
  811.  
  812.     // }}}
  813.     // {{{ autoPrepare()
  814.  
  815.     /**
  816.      * Automaticaly generate an insert or update query and pass it to prepare()
  817.      *
  818.      * @param string $table name of the table
  819.      * @param array $table_fields ordered array containing the fields names
  820.      * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE)
  821.      * @param string $where in case of update queries, this string will be put after the sql WHERE statement
  822.      * @return resource handle for the query
  823.      * @see DB_common::prepare(), DB_common::buildManipSQL()
  824.      * @access public
  825.      */
  826.     function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT, $where = false)
  827.     {
  828.         $query = $this->buildManipSQL($table, $table_fields, $mode, $where);
  829.         return $this->prepare($query);
  830.     }
  831.  
  832.     // }}}
  833.     // {{{ autoExecute()
  834.  
  835.     /**
  836.      * Automaticaly generate an insert or update query and call prepare()
  837.      * and execute() with it
  838.      *
  839.      * @param string $table name of the table
  840.      * @param array $fields_values assoc ($key=>$value) where $key is a field name and $value its value
  841.      * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE)
  842.      * @param string $where in case of update queries, this string will be put after the sql WHERE statement
  843.      * @return mixed  a new DB_Result or a DB_Error when fail
  844.      * @see DB_common::autoPrepare(), DB_common::buildManipSQL()
  845.      * @access public
  846.      */
  847.     function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT, $where = false)
  848.     {
  849.         $sth = $this->autoPrepare($table, array_keys($fields_values), $mode, $where);
  850.         $ret =& $this->execute($sth, array_values($fields_values));
  851.         $this->freePrepared($sth);
  852.         return $ret;
  853.  
  854.     }
  855.  
  856.     // }}}
  857.     // {{{ buildManipSQL()
  858.  
  859.     /**
  860.      * Make automaticaly an sql query for prepare()
  861.      *
  862.      * Example : buildManipSQL('table_sql', array('field1', 'field2', 'field3'), DB_AUTOQUERY_INSERT)
  863.      *           will return the string : INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?)
  864.      * NB : - This belongs more to a SQL Builder class, but this is a simple facility
  865.      *      - Be carefull ! If you don't give a $where param with an UPDATE query, all
  866.      *        the records of the table will be updated !
  867.      *
  868.      * @param string $table name of the table
  869.      * @param array $table_fields ordered array containing the fields names
  870.      * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE)
  871.      * @param string $where in case of update queries, this string will be put after the sql WHERE statement
  872.      * @return string sql query for prepare()
  873.      * @access public
  874.      */
  875.     function buildManipSQL($table, $table_fields, $mode, $where = false)
  876.     {
  877.         if (count($table_fields) == 0) {
  878.             $this->raiseError(DB_ERROR_NEED_MORE_DATA);
  879.         }
  880.         $first = true;
  881.         switch ($mode) {
  882.             case DB_AUTOQUERY_INSERT:
  883.                 $values = '';
  884.                 $names = '';
  885.                 foreach ($table_fields as $value) {
  886.                     if ($first) {
  887.                         $first = false;
  888.                     } else {
  889.                         $names .= ',';
  890.                         $values .= ',';
  891.                     }
  892.                     $names .= $value;
  893.                     $values .= '?';
  894.                 }
  895.                 return "INSERT INTO $table ($names) VALUES ($values)";
  896.             case DB_AUTOQUERY_UPDATE:
  897.                 $set = '';
  898.                 foreach ($table_fields as $value) {
  899.                     if ($first) {
  900.                         $first = false;
  901.                     } else {
  902.                         $set .= ',';
  903.                     }
  904.                     $set .= "$value = ?";
  905.                 }
  906.                 $sql = "UPDATE $table SET $set";
  907.                 if ($where) {
  908.                     $sql .= " WHERE $where";
  909.                 }
  910.                 return $sql;
  911.             default:
  912.                 $this->raiseError(DB_ERROR_SYNTAX);
  913.         }
  914.     }
  915.  
  916.     // }}}
  917.     // {{{ execute()
  918.  
  919.     /**
  920.      * Executes a DB statement prepared with prepare()
  921.      *
  922.      * Example 1.
  923.      * <code> <?php
  924.      * $sth = $dbh->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)');
  925.      * $data = array(
  926.      *     "John's text",
  927.      *     "'it''s good'",
  928.      *     'filename.txt'
  929.      * );
  930.      * $res =& $dbh->execute($sth, $data);
  931.      * ?></code>
  932.      *
  933.      * @param resource  $stmt  a DB statement resource returned from prepare()
  934.      * @param mixed  $data  array, string or numeric data to be used in
  935.      *                      execution of the statement.  Quantity of items
  936.      *                      passed must match quantity of placeholders in
  937.      *                      query:  meaning 1 placeholder for non-array
  938.      *                      parameters or 1 placeholder per array element.
  939.      *
  940.      * @return object  a new DB_Result or a DB_Error when fail
  941.      *
  942.      * {@internal ibase and oci8 have their own execute() methods.}}
  943.      *
  944.      * @see DB_common::prepare()
  945.      * @access public
  946.      */
  947.     function &execute($stmt, $data = array())
  948.     {
  949.         $realquery = $this->executeEmulateQuery($stmt, $data);
  950.         if (DB::isError($realquery)) {
  951.             return $realquery;
  952.         }
  953.         $result = $this->simpleQuery($realquery);
  954.  
  955.         if (DB::isError($result) || $result === DB_OK) {
  956.             return $result;
  957.         } else {
  958.             $tmp =& new DB_result($this, $result);
  959.             return $tmp;
  960.         }
  961.     }
  962.  
  963.     // }}}
  964.     // {{{ executeEmulateQuery()
  965.  
  966.     /**
  967.      * Emulates the execute statement, when not supported
  968.      *
  969.      * @param resource  $stmt  a DB statement resource returned from execute()
  970.      * @param mixed  $data  array, string or numeric data to be used in
  971.      *                      execution of the statement.  Quantity of items
  972.      *                      passed must match quantity of placeholders in
  973.      *                      query:  meaning 1 placeholder for non-array
  974.      *                      parameters or 1 placeholder per array element.
  975.      *
  976.      * @return mixed a string containing the real query run when emulating
  977.      *               prepare/execute.  A DB error code is returned on failure.
  978.      *
  979.      * @see DB_common::execute()
  980.      * @access private
  981.      */
  982.     function executeEmulateQuery($stmt, $data = array())
  983.     {
  984.         $stmt = (int)$stmt;
  985.         if (!is_array($data)) {
  986.             $data = array($data);
  987.         }
  988.  
  989.         if (count($this->prepare_types[$stmt]) != count($data)) {
  990.             $this->last_query = $this->prepared_queries[$stmt];
  991.             return $this->raiseError(DB_ERROR_MISMATCH);
  992.         }
  993.  
  994.         $realquery = $this->prepare_tokens[$stmt][0];
  995.  
  996.         $i = 0;
  997.         foreach ($data as $value) {
  998.             if ($this->prepare_types[$stmt][$i] == DB_PARAM_SCALAR) {
  999.                 $realquery .= $this->quoteSmart($value);
  1000.             } elseif ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) {
  1001.                 $fp = @fopen($value, 'rb');
  1002.                 if (!$fp) {
  1003.                     return $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
  1004.                 }
  1005.                 $realquery .= $this->quoteSmart(fread($fp, filesize($value)));
  1006.                 fclose($fp);
  1007.             } else {
  1008.                 $realquery .= $value;
  1009.             }
  1010.  
  1011.             $realquery .= $this->prepare_tokens[$stmt][++$i];
  1012.         }
  1013.  
  1014.         return $realquery;
  1015.     }
  1016.  
  1017.     // }}}
  1018.     // {{{ executeMultiple()
  1019.  
  1020.     /**
  1021.      * This function does several execute() calls on the same
  1022.      * statement handle
  1023.      *
  1024.      * $data must be an array indexed numerically
  1025.      * from 0, one execute call is done for every "row" in the array.
  1026.      *
  1027.      * If an error occurs during execute(), executeMultiple() does not
  1028.      * execute the unfinished rows, but rather returns that error.
  1029.      *
  1030.      * @param resource $stmt query handle from prepare()
  1031.      * @param array    $data numeric array containing the
  1032.      *                       data to insert into the query
  1033.      *
  1034.      * @return mixed DB_OK or DB_Error
  1035.      *
  1036.      * @see DB_common::prepare(), DB_common::execute()
  1037.      * @access public
  1038.      */
  1039.     function executeMultiple($stmt, $data)
  1040.     {
  1041.         foreach ($data as $value) {
  1042.             $res =& $this->execute($stmt, $value);
  1043.             if (DB::isError($res)) {
  1044.                 return $res;
  1045.             }
  1046.         }
  1047.         return DB_OK;
  1048.     }
  1049.  
  1050.     // }}}
  1051.     // {{{ freePrepared()
  1052.  
  1053.     /**
  1054.      * Free the resource used in a prepared query
  1055.      *
  1056.      * @param $stmt The resurce returned by the prepare() function
  1057.      * @see DB_common::prepare()
  1058.      */
  1059.     function freePrepared($stmt)
  1060.     {
  1061.         $stmt = (int)$stmt;
  1062.         // Free the internal prepared vars
  1063.         if (isset($this->prepare_tokens[$stmt])) {
  1064.             unset($this->prepare_tokens[$stmt]);
  1065.             unset($this->prepare_types[$stmt]);
  1066.             unset($this->prepared_queries[$stmt]);
  1067.             return true;
  1068.         }
  1069.         return false;
  1070.     }
  1071.  
  1072.     // }}}
  1073.     // {{{ modifyQuery()
  1074.  
  1075.     /**
  1076.      * This method is used by backends to alter queries for various
  1077.      * reasons
  1078.      *
  1079.      * It is defined here to assure that all implementations
  1080.      * have this method defined.
  1081.      *
  1082.      * @param string $query  query to modify
  1083.      *
  1084.      * @return the new (modified) query
  1085.      *
  1086.      * @access private
  1087.      */
  1088.     function modifyQuery($query) {
  1089.         return $query;
  1090.     }
  1091.  
  1092.     // }}}
  1093.     // {{{ modifyLimitQuery()
  1094.  
  1095.     /**
  1096.      * This method is used by backends to alter limited queries
  1097.      *
  1098.      * @param string  $query query to modify
  1099.      * @param integer $from  the row to start to fetching
  1100.      * @param integer $count the numbers of rows to fetch
  1101.      *
  1102.      * @return the new (modified) query
  1103.      *
  1104.      * @access private
  1105.      */
  1106.     function modifyLimitQuery($query, $from, $count, $params = array())
  1107.     {
  1108.         return $query;
  1109.     }
  1110.  
  1111.     // }}}
  1112.     // {{{ query()
  1113.  
  1114.     /**
  1115.      * Send a query to the database and return any results with a
  1116.      * DB_result object
  1117.      *
  1118.      * The query string can be either a normal statement to be sent directly
  1119.      * to the server OR if <var>$params</var> are passed the query can have
  1120.      * placeholders and it will be passed through prepare() and execute().
  1121.      *
  1122.      * @param string $query  the SQL query or the statement to prepare
  1123.      * @param mixed  $params array, string or numeric data to be used in
  1124.      *                       execution of the statement.  Quantity of items
  1125.      *                       passed must match quantity of placeholders in
  1126.      *                       query:  meaning 1 placeholder for non-array
  1127.      *                       parameters or 1 placeholder per array element.
  1128.      *
  1129.      * @return mixed  a DB_result object or DB_OK on success, a DB
  1130.      *                error on failure
  1131.      *
  1132.      * @see DB_result, DB_common::prepare(), DB_common::execute()
  1133.      * @access public
  1134.      */
  1135.     function &query($query, $params = array())
  1136.     {
  1137.         if (sizeof($params) > 0) {
  1138.             $sth = $this->prepare($query);
  1139.             if (DB::isError($sth)) {
  1140.                 return $sth;
  1141.             }
  1142.             $ret =& $this->execute($sth, $params);
  1143.             $this->freePrepared($sth);
  1144.             return $ret;
  1145.         } else {
  1146.             $result = $this->simpleQuery($query);
  1147.             if (DB::isError($result) || $result === DB_OK) {
  1148.                 return $result;
  1149.             } else {
  1150.                 $tmp =& new DB_result($this, $result);
  1151.                 return $tmp;
  1152.             }
  1153.         }
  1154.     }
  1155.  
  1156.     // }}}
  1157.     // {{{ limitQuery()
  1158.  
  1159.     /**
  1160.      * Generates a limited query
  1161.      *
  1162.      * @param string  $query query
  1163.      * @param integer $from  the row to start to fetching
  1164.      * @param integer $count the numbers of rows to fetch
  1165.      * @param mixed   $params array, string or numeric data to be used in
  1166.      *                       execution of the statement.  Quantity of items
  1167.      *                       passed must match quantity of placeholders in
  1168.      *                       query:  meaning 1 placeholder for non-array
  1169.      *                       parameters or 1 placeholder per array element.
  1170.      *
  1171.      * @return mixed a DB_Result object, DB_OK or a DB_Error
  1172.      *
  1173.      * @access public
  1174.      */
  1175.     function &limitQuery($query, $from, $count, $params = array())
  1176.     {
  1177.         $query = $this->modifyLimitQuery($query, $from, $count, $params);
  1178.         if (DB::isError($query)){
  1179.             return $query;
  1180.         }
  1181.         $result =& $this->query($query, $params);
  1182.         if (is_a($result, 'DB_result')) {
  1183.             $result->setOption('limit_from', $from);
  1184.             $result->setOption('limit_count', $count);
  1185.         }
  1186.         return $result;
  1187.     }
  1188.  
  1189.     // }}}
  1190.     // {{{ getOne()
  1191.  
  1192.     /**
  1193.      * Fetch the first column of the first row of data returned from
  1194.      * a query
  1195.      *
  1196.      * Takes care of doing the query and freeing the results when finished.
  1197.      *
  1198.      * @param string $query  the SQL query
  1199.      * @param mixed  $params array, string or numeric data to be used in
  1200.      *                       execution of the statement.  Quantity of items
  1201.      *                       passed must match quantity of placeholders in
  1202.      *                       query:  meaning 1 placeholder for non-array
  1203.      *                       parameters or 1 placeholder per array element.
  1204.      *
  1205.      * @return mixed  the returned value of the query.  DB_Error on failure.
  1206.      *
  1207.      * @access public
  1208.      */
  1209.     function &getOne($query, $params = array())
  1210.     {
  1211.         settype($params, 'array');
  1212.         if (sizeof($params) > 0) {
  1213.             $sth = $this->prepare($query);
  1214.             if (DB::isError($sth)) {
  1215.                 return $sth;
  1216.             }
  1217.             $res =& $this->execute($sth, $params);
  1218.             $this->freePrepared($sth);
  1219.         } else {
  1220.             $res =& $this->query($query);
  1221.         }
  1222.  
  1223.         if (DB::isError($res)) {
  1224.             return $res;
  1225.         }
  1226.  
  1227.         $err = $res->fetchInto($row, DB_FETCHMODE_ORDERED);
  1228.         $res->free();
  1229.  
  1230.         if ($err !== DB_OK) {
  1231.             return $err;
  1232.         }
  1233.  
  1234.         return $row[0];
  1235.     }
  1236.  
  1237.     // }}}
  1238.     // {{{ getRow()
  1239.  
  1240.     /**
  1241.      * Fetch the first row of data returned from a query
  1242.      *
  1243.      * Takes care of doing the query and freeing the results when finished.
  1244.      *
  1245.      * @param string $query  the SQL query
  1246.      * @param array  $params array to be used in execution of the statement.
  1247.      *                       Quantity of array elements must match quantity
  1248.      *                       of placeholders in query.  This function does
  1249.      *                       NOT support scalars.
  1250.      * @param int    $fetchmode  the fetch mode to use
  1251.      *
  1252.      * @return array the first row of results as an array indexed from
  1253.      *               0, or a DB error code.
  1254.      *
  1255.      * @access public
  1256.      */
  1257.     function &getRow($query,
  1258.                      $params = array(),
  1259.                      $fetchmode = DB_FETCHMODE_DEFAULT)
  1260.     {
  1261.         // compat check, the params and fetchmode parameters used to
  1262.         // have the opposite order
  1263.         if (!is_array($params)) {
  1264.             if (is_array($fetchmode)) {
  1265.                 if ($params === null) {
  1266.                     $tmp = DB_FETCHMODE_DEFAULT;
  1267.                 } else {
  1268.                     $tmp = $params;
  1269.                 }
  1270.                 $params = $fetchmode;
  1271.                 $fetchmode = $tmp;
  1272.             } elseif ($params !== null) {
  1273.                 $fetchmode = $params;
  1274.                 $params = array();
  1275.             }
  1276.         }
  1277.  
  1278.         if (sizeof($params) > 0) {
  1279.             $sth = $this->prepare($query);
  1280.             if (DB::isError($sth)) {
  1281.                 return $sth;
  1282.             }
  1283.             $res =& $this->execute($sth, $params);
  1284.             $this->freePrepared($sth);
  1285.         } else {
  1286.             $res =& $this->query($query);
  1287.         }
  1288.  
  1289.         if (DB::isError($res)) {
  1290.             return $res;
  1291.         }
  1292.  
  1293.         $err = $res->fetchInto($row, $fetchmode);
  1294.  
  1295.         $res->free();
  1296.  
  1297.         if ($err !== DB_OK) {
  1298.             return $err;
  1299.         }
  1300.  
  1301.         return $row;
  1302.     }
  1303.  
  1304.     // }}}
  1305.     // {{{ getCol()
  1306.  
  1307.     /**
  1308.      * Fetch a single column from a result set and return it as an
  1309.      * indexed array
  1310.      *
  1311.      * @param string $query  the SQL query
  1312.      * @param mixed  $col    which column to return (integer [column number,
  1313.      *                       starting at 0] or string [column name])
  1314.      * @param mixed  $params array, string or numeric data to be used in
  1315.      *                       execution of the statement.  Quantity of items
  1316.      *                       passed must match quantity of placeholders in
  1317.      *                       query:  meaning 1 placeholder for non-array
  1318.      *                       parameters or 1 placeholder per array element.
  1319.      *
  1320.      * @return array  an indexed array with the data from the first
  1321.      *                row at index 0, or a DB error code
  1322.      *
  1323.      * @see DB_common::query()
  1324.      * @access public
  1325.      */
  1326.     function &getCol($query, $col = 0, $params = array())
  1327.     {
  1328.         settype($params, 'array');
  1329.         if (sizeof($params) > 0) {
  1330.             $sth = $this->prepare($query);
  1331.  
  1332.             if (DB::isError($sth)) {
  1333.                 return $sth;
  1334.             }
  1335.  
  1336.             $res =& $this->execute($sth, $params);
  1337.             $this->freePrepared($sth);
  1338.         } else {
  1339.             $res =& $this->query($query);
  1340.         }
  1341.  
  1342.         if (DB::isError($res)) {
  1343.             return $res;
  1344.         }
  1345.  
  1346.         $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC;
  1347.  
  1348.         if (!is_array($row = $res->fetchRow($fetchmode))) {
  1349.             $ret = array();
  1350.         } else {
  1351.             if (!array_key_exists($col, $row)) {
  1352.                 $ret =& $this->raiseError(DB_ERROR_NOSUCHFIELD);
  1353.             } else {
  1354.                 $ret = array($row[$col]);
  1355.                 while (is_array($row = $res->fetchRow($fetchmode))) {
  1356.                     $ret[] = $row[$col];
  1357.                 }
  1358.             }
  1359.         }
  1360.  
  1361.         $res->free();
  1362.  
  1363.         if (DB::isError($row)) {
  1364.             $ret = $row;
  1365.         }
  1366.  
  1367.         return $ret;
  1368.     }
  1369.  
  1370.     // }}}
  1371.     // {{{ getAssoc()
  1372.  
  1373.     /**
  1374.      * Fetch the entire result set of a query and return it as an
  1375.      * associative array using the first column as the key
  1376.      *
  1377.      * If the result set contains more than two columns, the value
  1378.      * will be an array of the values from column 2-n.  If the result
  1379.      * set contains only two columns, the returned value will be a
  1380.      * scalar with the value of the second column (unless forced to an
  1381.      * array with the $force_array parameter).  A DB error code is
  1382.      * returned on errors.  If the result set contains fewer than two
  1383.      * columns, a DB_ERROR_TRUNCATED error is returned.
  1384.      *
  1385.      * For example, if the table "mytable" contains:
  1386.      *
  1387.      * <pre>
  1388.      *  ID      TEXT       DATE
  1389.      * --------------------------------
  1390.      *  1       'one'      944679408
  1391.      *  2       'two'      944679408
  1392.      *  3       'three'    944679408
  1393.      * </pre>
  1394.      *
  1395.      * Then the call getAssoc('SELECT id,text FROM mytable') returns:
  1396.      * <pre>
  1397.      *   array(
  1398.      *     '1' => 'one',
  1399.      *     '2' => 'two',
  1400.      *     '3' => 'three',
  1401.      *   )
  1402.      * </pre>
  1403.      *
  1404.      * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns:
  1405.      * <pre>
  1406.      *   array(
  1407.      *     '1' => array('one', '944679408'),
  1408.      *     '2' => array('two', '944679408'),
  1409.      *     '3' => array('three', '944679408')
  1410.      *   )
  1411.      * </pre>
  1412.      *
  1413.      * If the more than one row occurs with the same value in the
  1414.      * first column, the last row overwrites all previous ones by
  1415.      * default.  Use the $group parameter if you don't want to
  1416.      * overwrite like this.  Example:
  1417.      *
  1418.      * <pre>
  1419.      * getAssoc('SELECT category,id,name FROM mytable', false, null,
  1420.      *          DB_FETCHMODE_ASSOC, true) returns:
  1421.      *
  1422.      *   array(
  1423.      *     '1' => array(array('id' => '4', 'name' => 'number four'),
  1424.      *                  array('id' => '6', 'name' => 'number six')
  1425.      *            ),
  1426.      *     '9' => array(array('id' => '4', 'name' => 'number four'),
  1427.      *                  array('id' => '6', 'name' => 'number six')
  1428.      *            )
  1429.      *   )
  1430.      * </pre>
  1431.      *
  1432.      * Keep in mind that database functions in PHP usually return string
  1433.      * values for results regardless of the database's internal type.
  1434.      *
  1435.      * @param string  $query  the SQL query
  1436.      * @param boolean $force_array  used only when the query returns
  1437.      *                              exactly two columns.  If true, the values
  1438.      *                              of the returned array will be one-element
  1439.      *                              arrays instead of scalars.
  1440.      * @param mixed   $params array, string or numeric data to be used in
  1441.      *                        execution of the statement.  Quantity of items
  1442.      *                        passed must match quantity of placeholders in
  1443.      *                        query:  meaning 1 placeholder for non-array
  1444.      *                        parameters or 1 placeholder per array element.
  1445.      * @param int     $fetchmode  the fetch mode to use
  1446.      * @param boolean $group  if true, the values of the returned array
  1447.      *                        is wrapped in another array.  If the same
  1448.      *                        key value (in the first column) repeats
  1449.      *                        itself, the values will be appended to
  1450.      *                        this array instead of overwriting the
  1451.      *                        existing values.
  1452.      *
  1453.      * @return array  associative array with results from the query.
  1454.      *                DB Error on failure.
  1455.      *
  1456.      * @access public
  1457.      */
  1458.     function &getAssoc($query, $force_array = false, $params = array(),
  1459.                        $fetchmode = DB_FETCHMODE_DEFAULT, $group = false)
  1460.     {
  1461.         settype($params, 'array');
  1462.         if (sizeof($params) > 0) {
  1463.             $sth = $this->prepare($query);
  1464.  
  1465.             if (DB::isError($sth)) {
  1466.                 return $sth;
  1467.             }
  1468.  
  1469.             $res =& $this->execute($sth, $params);
  1470.             $this->freePrepared($sth);
  1471.         } else {
  1472.             $res =& $this->query($query);
  1473.         }
  1474.  
  1475.         if (DB::isError($res)) {
  1476.             return $res;
  1477.         }
  1478.         if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  1479.             $fetchmode = $this->fetchmode;
  1480.         }
  1481.         $cols = $res->numCols();
  1482.  
  1483.         if ($cols < 2) {
  1484.             $tmp =& $this->raiseError(DB_ERROR_TRUNCATED);
  1485.             return $tmp;
  1486.         }
  1487.  
  1488.         $results = array();
  1489.  
  1490.         if ($cols > 2 || $force_array) {
  1491.             // return array values
  1492.             // XXX this part can be optimized
  1493.             if ($fetchmode == DB_FETCHMODE_ASSOC) {
  1494.                 while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) {
  1495.                     reset($row);
  1496.                     $key = current($row);
  1497.                     unset($row[key($row)]);
  1498.                     if ($group) {
  1499.                         $results[$key][] = $row;
  1500.                     } else {
  1501.                         $results[$key] = $row;
  1502.                     }
  1503.                 }
  1504.             } elseif ($fetchmode == DB_FETCHMODE_OBJECT) {
  1505.                 while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) {
  1506.                     $arr = get_object_vars($row);
  1507.                     $key = current($arr);
  1508.                     if ($group) {
  1509.                         $results[$key][] = $row;
  1510.                     } else {
  1511.                         $results[$key] = $row;
  1512.                     }
  1513.                 }
  1514.             } else {
  1515.                 while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) {
  1516.                     // we shift away the first element to get
  1517.                     // indices running from 0 again
  1518.                     $key = array_shift($row);
  1519.                     if ($group) {
  1520.                         $results[$key][] = $row;
  1521.                     } else {
  1522.                         $results[$key] = $row;
  1523.                     }
  1524.                 }
  1525.             }
  1526.             if (DB::isError($row)) {
  1527.                 $results = $row;
  1528.             }
  1529.         } else {
  1530.             // return scalar values
  1531.             while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) {
  1532.                 if ($group) {
  1533.                     $results[$row[0]][] = $row[1];
  1534.                 } else {
  1535.                     $results[$row[0]] = $row[1];
  1536.                 }
  1537.             }
  1538.             if (DB::isError($row)) {
  1539.                 $results = $row;
  1540.             }
  1541.         }
  1542.  
  1543.         $res->free();
  1544.  
  1545.         return $results;
  1546.     }
  1547.  
  1548.     // }}}
  1549.     // {{{ getAll()
  1550.  
  1551.     /**
  1552.      * Fetch all the rows returned from a query
  1553.      *
  1554.      * @param string $query  the SQL query
  1555.      * @param array  $params array to be used in execution of the statement.
  1556.      *                       Quantity of array elements must match quantity
  1557.      *                       of placeholders in query.  This function does
  1558.      *                       NOT support scalars.
  1559.      * @param int    $fetchmode  the fetch mode to use
  1560.      *
  1561.      * @return array  an nested array.  DB error on failure.
  1562.      *
  1563.      * @access public
  1564.      */
  1565.     function &getAll($query,
  1566.                      $params = array(),
  1567.                      $fetchmode = DB_FETCHMODE_DEFAULT)
  1568.     {
  1569.         // compat check, the params and fetchmode parameters used to
  1570.         // have the opposite order
  1571.         if (!is_array($params)) {
  1572.             if (is_array($fetchmode)) {
  1573.                 if ($params === null) {
  1574.                     $tmp = DB_FETCHMODE_DEFAULT;
  1575.                 } else {
  1576.                     $tmp = $params;
  1577.                 }
  1578.                 $params = $fetchmode;
  1579.                 $fetchmode = $tmp;
  1580.             } elseif ($params !== null) {
  1581.                 $fetchmode = $params;
  1582.                 $params = array();
  1583.             }
  1584.         }
  1585.  
  1586.         if (sizeof($params) > 0) {
  1587.             $sth = $this->prepare($query);
  1588.  
  1589.             if (DB::isError($sth)) {
  1590.                 return $sth;
  1591.             }
  1592.  
  1593.             $res =& $this->execute($sth, $params);
  1594.             $this->freePrepared($sth);
  1595.         } else {
  1596.             $res =& $this->query($query);
  1597.         }
  1598.  
  1599.         if (DB::isError($res) || $res === DB_OK) {
  1600.             return $res;
  1601.         }
  1602.  
  1603.         $results = array();
  1604.         while (DB_OK === $res->fetchInto($row, $fetchmode)) {
  1605.             if ($fetchmode & DB_FETCHMODE_FLIPPED) {
  1606.                 foreach ($row as $key => $val) {
  1607.                     $results[$key][] = $val;
  1608.                 }
  1609.             } else {
  1610.                 $results[] = $row;
  1611.             }
  1612.         }
  1613.  
  1614.         $res->free();
  1615.  
  1616.         if (DB::isError($row)) {
  1617.             $tmp =& $this->raiseError($row);
  1618.             return $tmp;
  1619.         }
  1620.         return $results;
  1621.     }
  1622.  
  1623.     // }}}
  1624.     // {{{ autoCommit()
  1625.  
  1626.     /**
  1627.      * enable automatic Commit
  1628.      *
  1629.      * @param boolean $onoff
  1630.      * @return mixed DB_Error
  1631.      *
  1632.      * @access public
  1633.      */
  1634.     function autoCommit($onoff=false)
  1635.     {
  1636.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1637.     }
  1638.  
  1639.     // }}}
  1640.     // {{{ commit()
  1641.  
  1642.     /**
  1643.      * starts a Commit
  1644.      *
  1645.      * @return mixed DB_Error
  1646.      *
  1647.      * @access public
  1648.      */
  1649.     function commit()
  1650.     {
  1651.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1652.     }
  1653.  
  1654.     // }}}
  1655.     // {{{ rollback()
  1656.  
  1657.     /**
  1658.      * starts a rollback
  1659.      *
  1660.      * @return mixed DB_Error
  1661.      *
  1662.      * @access public
  1663.      */
  1664.     function rollback()
  1665.     {
  1666.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1667.     }
  1668.  
  1669.     // }}}
  1670.     // {{{ numRows()
  1671.  
  1672.     /**
  1673.      * Returns the number of rows in a result object
  1674.      *
  1675.      * @param object DB_Result the result object to check
  1676.      *
  1677.      * @return mixed DB_Error or the number of rows
  1678.      *
  1679.      * @access public
  1680.      */
  1681.     function numRows($result)
  1682.     {
  1683.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1684.     }
  1685.  
  1686.     // }}}
  1687.     // {{{ affectedRows()
  1688.  
  1689.     /**
  1690.      * Returns the affected rows of a query
  1691.      *
  1692.      * @return mixed DB_Error or number of rows
  1693.      *
  1694.      * @access public
  1695.      */
  1696.     function affectedRows()
  1697.     {
  1698.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1699.     }
  1700.  
  1701.     // }}}
  1702.     // {{{ errorNative()
  1703.  
  1704.     /**
  1705.      * Returns an errormessage, provides by the database
  1706.      *
  1707.      * @return mixed DB_Error or message
  1708.      *
  1709.      * @access public
  1710.      */
  1711.     function errorNative()
  1712.     {
  1713.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1714.     }
  1715.  
  1716.     // }}}
  1717.     // {{{ getSequenceName()
  1718.  
  1719.     /**
  1720.      * Generate the name used inside the database for a sequence
  1721.      *
  1722.      * The createSequence() docblock contains notes about storing sequence
  1723.      * names.
  1724.      *
  1725.      * @param string $sqn  the sequence's public name
  1726.      *
  1727.      * @return string  the sequence's name in the backend
  1728.      *
  1729.      * @see DB_common::createSequence(), DB_common::dropSequence(),
  1730.      *      DB_common::nextID(), DB_common::setOption()
  1731.      * @access private
  1732.      */
  1733.     function getSequenceName($sqn)
  1734.     {
  1735.         return sprintf($this->getOption('seqname_format'),
  1736.                        preg_replace('/[^a-z0-9_.]/i', '_', $sqn));
  1737.     }
  1738.  
  1739.     // }}}
  1740.     // {{{ nextId()
  1741.  
  1742.     /**
  1743.      * Returns the next free id in a sequence
  1744.      *
  1745.      * @param string  $seq_name  name of the sequence
  1746.      * @param boolean $ondemand  when true, the seqence is automatically
  1747.      *                           created if it does not exist
  1748.      *
  1749.      * @return int  the next id number in the sequence.  DB_Error if problem.
  1750.      *
  1751.      * @see DB_common::createSequence(), DB_common::dropSequence(),
  1752.      *      DB_common::getSequenceName()
  1753.      * @access public
  1754.      */
  1755.     function nextId($seq_name, $ondemand = true)
  1756.     {
  1757.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1758.     }
  1759.  
  1760.     // }}}
  1761.     // {{{ createSequence()
  1762.  
  1763.     /**
  1764.      * Creates a new sequence
  1765.      *
  1766.      * The name of a given sequence is determined by passing the string
  1767.      * provided in the <var>$seq_name</var> argument through PHP's sprintf()
  1768.      * function using the value from the <var>seqname_format</var> option as
  1769.      * the sprintf()'s format argument.
  1770.      *
  1771.      * <var>seqname_format</var> is set via setOption().
  1772.      *
  1773.      * @param string $seq_name  name of the new sequence
  1774.      *
  1775.      * @return int  DB_OK on success.  A DB_Error object is returned if
  1776.      *              problems arise.
  1777.      *
  1778.      * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  1779.      *      DB_common::nextID()
  1780.      * @access public
  1781.      */
  1782.     function createSequence($seq_name)
  1783.     {
  1784.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1785.     }
  1786.  
  1787.     // }}}
  1788.     // {{{ dropSequence()
  1789.  
  1790.     /**
  1791.      * Deletes a sequence
  1792.      *
  1793.      * @param string $seq_name  name of the sequence to be deleted
  1794.      *
  1795.      * @return int  DB_OK on success.  DB_Error if problems.
  1796.      *
  1797.      * @see DB_common::createSequence(), DB_common::getSequenceName(),
  1798.      *      DB_common::nextID()
  1799.      * @access public
  1800.      */
  1801.     function dropSequence($seq_name)
  1802.     {
  1803.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1804.     }
  1805.  
  1806.     // }}}
  1807.     // {{{ tableInfo()
  1808.  
  1809.     /**
  1810.      * Returns information about a table or a result set
  1811.      *
  1812.      * The format of the resulting array depends on which <var>$mode</var>
  1813.      * you select.  The sample output below is based on this query:
  1814.      * <pre>
  1815.      *    SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
  1816.      *    FROM tblFoo
  1817.      *    JOIN tblBar ON tblFoo.fldId = tblBar.fldId
  1818.      * </pre>
  1819.      *
  1820.      * <ul>
  1821.      * <li>
  1822.      *
  1823.      * <kbd>null</kbd> (default)
  1824.      *   <pre>
  1825.      *   [0] => Array (
  1826.      *       [table] => tblFoo
  1827.      *       [name] => fldId
  1828.      *       [type] => int
  1829.      *       [len] => 11
  1830.      *       [flags] => primary_key not_null
  1831.      *   )
  1832.      *   [1] => Array (
  1833.      *       [table] => tblFoo
  1834.      *       [name] => fldPhone
  1835.      *       [type] => string
  1836.      *       [len] => 20
  1837.      *       [flags] =>
  1838.      *   )
  1839.      *   [2] => Array (
  1840.      *       [table] => tblBar
  1841.      *       [name] => fldId
  1842.      *       [type] => int
  1843.      *       [len] => 11
  1844.      *       [flags] => primary_key not_null
  1845.      *   )
  1846.      *   </pre>
  1847.      *
  1848.      * </li><li>
  1849.      *
  1850.      * <kbd>DB_TABLEINFO_ORDER</kbd>
  1851.      *
  1852.      *   <p>In addition to the information found in the default output,
  1853.      *   a notation of the number of columns is provided by the
  1854.      *   <samp>num_fields</samp> element while the <samp>order</samp>
  1855.      *   element provides an array with the column names as the keys and
  1856.      *   their location index number (corresponding to the keys in the
  1857.      *   the default output) as the values.</p>
  1858.      *
  1859.      *   <p>If a result set has identical field names, the last one is
  1860.      *   used.</p>
  1861.      *
  1862.      *   <pre>
  1863.      *   [num_fields] => 3
  1864.      *   [order] => Array (
  1865.      *       [fldId] => 2
  1866.      *       [fldTrans] => 1
  1867.      *   )
  1868.      *   </pre>
  1869.      *
  1870.      * </li><li>
  1871.      *
  1872.      * <kbd>DB_TABLEINFO_ORDERTABLE</kbd>
  1873.      *
  1874.      *   <p>Similar to <kbd>DB_TABLEINFO_ORDER</kbd> but adds more
  1875.      *   dimensions to the array in which the table names are keys and
  1876.      *   the field names are sub-keys.  This is helpful for queries that
  1877.      *   join tables which have identical field names.</p>
  1878.      *
  1879.      *   <pre>
  1880.      *   [num_fields] => 3
  1881.      *   [ordertable] => Array (
  1882.      *       [tblFoo] => Array (
  1883.      *           [fldId] => 0
  1884.      *           [fldPhone] => 1
  1885.      *       )
  1886.      *       [tblBar] => Array (
  1887.      *           [fldId] => 2
  1888.      *       )
  1889.      *   )
  1890.      *   </pre>
  1891.      *
  1892.      * </li>
  1893.      * </ul>
  1894.      *
  1895.      * The <samp>flags</samp> element contains a space separated list
  1896.      * of extra information about the field.  This data is inconsistent
  1897.      * between DBMS's due to the way each DBMS works.
  1898.      *   + <samp>primary_key</samp>
  1899.      *   + <samp>unique_key</samp>
  1900.      *   + <samp>multiple_key</samp>
  1901.      *   + <samp>not_null</samp>
  1902.      *
  1903.      * Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp>
  1904.      * elements if <var>$result</var> is a table name.  The following DBMS's
  1905.      * provide full information from queries:
  1906.      *   + fbsql
  1907.      *   + mysql
  1908.      *
  1909.      * If the 'portability' option has <samp>DB_PORTABILITY_LOWERCASE</samp>
  1910.      * turned on, the names of tables and fields will be lowercased.
  1911.      *
  1912.      * @param object|string  $result  DB_result object from a query or a
  1913.      *                                string containing the name of a table.
  1914.      *                                While this also accepts a query result
  1915.      *                                resource identifier, this behavior is
  1916.      *                                deprecated.
  1917.      * @param int  $mode   either unused or one of the tableInfo modes:
  1918.      *                     <kbd>DB_TABLEINFO_ORDERTABLE</kbd>,
  1919.      *                     <kbd>DB_TABLEINFO_ORDER</kbd> or
  1920.      *                     <kbd>DB_TABLEINFO_FULL</kbd> (which does both).
  1921.      *                     These are bitwise, so the first two can be
  1922.      *                     combined using <kbd>|</kbd>.
  1923.      * @return array  an associative array with the information requested.
  1924.      *                If something goes wrong an error object is returned.
  1925.      *
  1926.      * @see DB_common::setOption()
  1927.      * @access public
  1928.      */
  1929.     function tableInfo($result, $mode = null)
  1930.     {
  1931.         /*
  1932.          * If the DB_<driver> class has a tableInfo() method, that one
  1933.          * overrides this one.  But, if the driver doesn't have one,
  1934.          * this method runs and tells users about that fact.
  1935.          */
  1936.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1937.     }
  1938.  
  1939.     // }}}
  1940.     // {{{ getTables()
  1941.  
  1942.     /**
  1943.      * @deprecated  Deprecated in release 1.2 or lower
  1944.      */
  1945.     function getTables()
  1946.     {
  1947.         return $this->getListOf('tables');
  1948.     }
  1949.  
  1950.     // }}}
  1951.     // {{{ getListOf()
  1952.  
  1953.     /**
  1954.      * list internal DB info
  1955.      * valid values for $type are db dependent,
  1956.      * often: databases, users, view, functions
  1957.      *
  1958.      * @param string $type type of requested info
  1959.      *
  1960.      * @return mixed DB_Error or the requested data
  1961.      *
  1962.      * @access public
  1963.      */
  1964.     function getListOf($type)
  1965.     {
  1966.         $sql = $this->getSpecialQuery($type);
  1967.         if ($sql === null) {                                // No support
  1968.             return $this->raiseError(DB_ERROR_UNSUPPORTED);
  1969.         } elseif (is_int($sql) || DB::isError($sql)) {      // Previous error
  1970.             return $this->raiseError($sql);
  1971.         } elseif (is_array($sql)) {                         // Already the result
  1972.             return $sql;
  1973.         }
  1974.         return $this->getCol($sql);                         // Launch this query
  1975.     }
  1976.  
  1977.     // }}}
  1978.     // {{{ getSpecialQuery()
  1979.  
  1980.     /**
  1981.      * Returns the query needed to get some backend info
  1982.      *
  1983.      * @param string $type What kind of info you want to retrieve
  1984.      *
  1985.      * @return string The SQL query string
  1986.      *
  1987.      * @access public
  1988.      */
  1989.     function getSpecialQuery($type)
  1990.     {
  1991.         return $this->raiseError(DB_ERROR_UNSUPPORTED);
  1992.     }
  1993.  
  1994.     // }}}
  1995.     // {{{ _rtrimArrayValues()
  1996.  
  1997.     /**
  1998.      * Right trim all strings in an array
  1999.      *
  2000.      * @param array  $array  the array to be trimmed (passed by reference)
  2001.      * @return void
  2002.      * @access private
  2003.      */
  2004.     function _rtrimArrayValues(&$array)
  2005.     {
  2006.         foreach ($array as $key => $value) {
  2007.             if (is_string($value)) {
  2008.                 $array[$key] = rtrim($value);
  2009.             }
  2010.         }
  2011.     }
  2012.  
  2013.     // }}}
  2014.     // {{{ _convertNullArrayValuesToEmpty()
  2015.  
  2016.     /**
  2017.      * Convert all null values in an array to empty strings
  2018.      *
  2019.      * @param array  $array  the array to be de-nullified (passed by reference)
  2020.      * @return void
  2021.      * @access private
  2022.      */
  2023.     function _convertNullArrayValuesToEmpty(&$array)
  2024.     {
  2025.         foreach ($array as $key => $value) {
  2026.             if (is_null($value)) {
  2027.                 $array[$key] = '';
  2028.             }
  2029.         }
  2030.     }
  2031.  
  2032.     // }}}
  2033. }
  2034.  
  2035. /*
  2036.  * Local variables:
  2037.  * tab-width: 4
  2038.  * c-basic-offset: 4
  2039.  * End:
  2040.  */
  2041.  
  2042. ?>
  2043.